
package com.efast.cafe.commponent.es.tcp.configuration;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.context.event.ContextRefreshedEvent;

import com.efast.cafe.commponent.es.tcp.annotation.TcpHandler;
import com.efast.cafe.commponent.es.tcp.channel.TcpChannelChannel;
import com.efast.cafe.commponent.es.tcp.properties.TcpConfig;
import com.efast.cafe.commponent.es.tcp.utils.CommandConstant;
import com.efast.cafe.commponent.log.ext.CafeLogger;
import com.efast.cafe.commponent.log.ext.CafeLoggerFactory;
import com.efast.cafe.util.BeanDefinitionFilter;
import com.efast.cafe.util.SpringUtils;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;


/**
 * 
    * @ClassName: TcpStarterConfiguration
    * @Description:tcp服务启动类
 */
@ConditionalOnProperty(
        name="tcp.enable",
        havingValue="true"
)
@Configuration
@AutoConfigureAfter(TcpConfig.class)
public class TcpStarterConfiguration implements ApplicationListener<ContextRefreshedEvent>{
	
	CafeLogger logger = CafeLoggerFactory.getLogger(getClass());
	
	private boolean isReady = false;
	
	@Autowired
	private TcpConfig config;
	
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		ApplicationContext ctx = event.getApplicationContext();
		try {
			if(!isReady){
				startTCPServer(ctx);
				isReady = true;
			}
		} catch (Exception e) {
			logger.error("startSocketServer 异常",e);
		}
	}
	
	
	private void startTCPServer(ApplicationContext ctx)throws Exception{
		SpringUtils springUtils = SpringUtils.getInstance(ctx);
		if(null!=config.getHandlerPackage()){
			for(String packageStr : config.getHandlerPackage()){
				Set<BeanDefinition> candidateComponents = springUtils.findCandidateComponents(packageStr,
						new BeanDefinitionFilter() {
							public boolean filter(ScannedGenericBeanDefinition sbd) {
								try {
									GenericBeanDefinition definition = sbd;
									Class<?> entityClazz = Class.forName(definition.getBeanClassName());
									TcpHandler annotation = (TcpHandler) entityClazz
											.getAnnotation(TcpHandler.class);
									if (annotation == null) {
										return false;
									}
									return true;
								} catch (ClassNotFoundException e) {
									e.printStackTrace();
								}
								return false;
							}
						});
				for (BeanDefinition beanDefinition : candidateComponents) {
					GenericBeanDefinition definition = (GenericBeanDefinition) beanDefinition;
					Class<?> interfaceClazz = Class.forName(definition.getBeanClassName());
					TcpHandler annotation =  interfaceClazz.getAnnotation(TcpHandler.class);
					if(annotation!=null){
						String command = new String(annotation.command(),"utf-8");
						CommandConstant.setHandler(command+annotation.version(), interfaceClazz.getName());
					}
				}
			}
		}
		
		 try {  
			 	EventLoopGroup bossGroup = new NioEventLoopGroup(config.getConnectLoop()); //客户端的连接线程池 
				EventLoopGroup workerGroup = new NioEventLoopGroup(config.getProcLoop()); //处理网络io 执行业务线程池
	            ServerBootstrap b = new ServerBootstrap();  
	            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
	            .option(ChannelOption.SO_BACKLOG,1024).childHandler(new TcpChannelChannel()); 
	            ChannelFuture future = b.bind(config.getPort()).sync(); 
	            logger.info("Netty time Server started at tcp port " + config.getPort());  
	            //future.channel().closeFuture().sync();
	        } catch(Exception e) {  
	           logger.error("启动tcp端口:"+config.getPort()+"，失败", e);
	        } 
		
	}
}
